package su.msk.jet.team01.chatik.server.commands.authorized;

import java.sql.SQLDataException;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import su.msk.jet.team01.chatik.server.data.Client;
import su.msk.jet.team01.chatik.server.db.DatabaseAdapter;

public class GetHistoryCommand extends AuthorizedCommand {
	private static final String CLIENT_INFO_MSG_NO_HISTORY_DAYS = "No history days available";
	private static final String CLIENT_INFO_MSG_NO_HISTORY_FOUND_FOR_DAY = "No history found for that date";
	private static final String CLIENT_INFO_MSG_HISTORY_DAYS_LIST_HEADER = "History days available: ";
	private static final String CLIENT_INFO_MSG_FAILED_GET_HISTORY_FOR_DAY = "Can't get history day";
	private static final String CLIENT_INFO_MSG_INVALID_DATE_FORMAT = "Invalid date specified";
	private static final String SQL_QUERY_SELECT_HISTORY_DATES = "SELECT DISTINCT date FROM history WHERE sender=? OR receiver=?";
	private static final String SQL_QUERY_SELECT_MESSAGES_HISTORY = "SELECT date, time, sender, receiver, message FROM history WHERE (sender=? OR receiver=?) AND date=?";

	private static DatabaseAdapter database = DatabaseAdapter.getInstance();

	private static Logger logger = LoggerFactory
			.getLogger(GetHistoryCommand.class);

	public GetHistoryCommand() {
		super("history", 0, 1);
	}

	@Override
	public void executeAuthorized(final Client client, final String[] args) {
		String date;

		if (args.length == 0) {
			try {
				client.send(translateHistoryDays(listHistoryDays(client
						.getName())));
			} catch (SQLException e) {
				client.send("Can't list history days");
				logger.error("Can't list history days (client: "
						+ client.getName() + ")" + ". Error message: "
						+ e.getMessage());
			}
		} else {
			date = args[0];
			try {
				client.send(translateHistoryDay(getHistoryDay(client.getName(),
						date)));
			} catch (SQLDataException e) {
				client.send(CLIENT_INFO_MSG_INVALID_DATE_FORMAT);
			} catch (SQLException e) {
				client.send(CLIENT_INFO_MSG_FAILED_GET_HISTORY_FOR_DAY);
				logger.error("Can't get history day (client: "
						+ client.getName() + ")" + ". Error message: "
						+ e.getMessage());
			} catch (ParseException e) {
				client.send(CLIENT_INFO_MSG_INVALID_DATE_FORMAT);
			}
		}
	}

	private List<String> getHistoryDay(final String clientName,
			final String date) throws ParseException, SQLException {
		String query = SQL_QUERY_SELECT_MESSAGES_HISTORY;
		List<Map<String, Object>> table;
		Map<String, Object> row;
		List<String> result = new ArrayList<String>();
		SimpleDateFormat dateFormatter = new SimpleDateFormat("dd-MM-yyyy");
		SimpleDateFormat timeFormatter = new SimpleDateFormat("HH:mm:ss");
		java.sql.Date dbDate;
		java.sql.Time dbTime;
		String fromName;
		String toName;
		String message;

		table = database.executeQuery(query, clientName, clientName,
				new java.sql.Date(dateFormatter.parse(date).getTime()));
		for (int i = 0; i < table.size(); i++) {
			row = table.get(i);
			dbDate = (java.sql.Date) row.get("DATE");
			dbTime = (java.sql.Time) row.get("TIME");
			fromName = (String) row.get("SENDER");
			toName = (String) row.get("RECEIVER");
			message = (String) row.get("MESSAGE");
			result.add(String.format("[%s %s] %s (private) %s: %s",
					dateFormatter.format(dbDate), timeFormatter.format(dbTime),
					fromName, toName, message));
		}

		return result;
	}

	private List<String> listHistoryDays(final String clientName)
			throws SQLException {
		String query = SQL_QUERY_SELECT_HISTORY_DATES;
		List<Map<String, Object>> table;
		Map<String, Object> row;
		List<String> result = new ArrayList<String>();
		SimpleDateFormat dateFormatter = new SimpleDateFormat("dd-MM-yyyy");
		java.sql.Date date;

		table = database.executeQuery(query, clientName, clientName);
		for (int i = 0; i < table.size(); i++) {
			row = table.get(i);
			date = (java.sql.Date) row.get("DATE");
			result.add(String.format("%s", dateFormatter.format(date)));
		}

		return result;
	}

	private String translateHistoryDay(final List<String> list) {
		StringBuilder result = new StringBuilder();

		if (list.size() > 0) {
			for (String message : list) {
				result.append(message);
				result.append("\n");
			}
			result.delete(result.length() - 1, result.length());
		} else {
			result.append(CLIENT_INFO_MSG_NO_HISTORY_FOUND_FOR_DAY);
		}

		return result.toString();
	}

	private String translateHistoryDays(final List<String> list) {
		StringBuilder result = new StringBuilder();

		if (list.size() > 0) {
			result.append(CLIENT_INFO_MSG_HISTORY_DAYS_LIST_HEADER);
			for (String key : list) {
				result.append(key).append(", ");
			}
			result.delete(result.length() - 2, result.length());
		} else {
			result.append(CLIENT_INFO_MSG_NO_HISTORY_DAYS);
		}

		return result.toString();
	}
}
